package points

import (
	"context"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"os"
	"sort"
	"strconv"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"github.com/golang-module/carbon"
	"gorm.io/gorm"
)

// 永旺积分
type YongWangPoints struct {
	PointsInterface
}

const (
	// 重要参数
	KEYWORDS_APPID      = "" // 应用id
	KEYWORDS_STORE_CODE = "" // 门店编码
	KEYWORDS_VERSION    = "" // 版本号

	// 公共参数
	IS_PROD        = false // 是否生产环境
	URL_TEST       = "https://sit-open.aeonbuy.com"
	URL_PROD       = "https://open.aeonbuy.com"
	HEADER_APPID   = "x-http-appid"   // appId
	HEADER_SIGN    = "x-http-sign"    // 签名
	HEADER_VERSION = "x-http-version" // 版本

	// API
	API_MEMBER_AUTH         = ""                                           // 1 会员授权请求
	API_MEMBER_AUTH_MESSAGE = "/api/open-api/open/member/auth/getByTicket" // 2 根据票据获取会员授权信息
	API_MEMBER_QUERY        = "/api/open-api/open/member/get"              // 3 会员查询
	API_POINTS_CONSUME      = "/api/open-api/open/point/use"               // 5 会员积分使用
	API_POINTS_REVERSE      = "/api/open-api/open/point/useReverse"        // 6 会员积分冲正
	API_POINTS_QUERY        = "/api/open-api/open/point/get"               // 7 会员积分查询
	API_ORDER_CREATE        = "/api/open-api/open/member/order/create"     // 10 预订单创建
	API_ORDER_CANCEL        = "/api/open-api/open/member/order/cancel"     // 12 订单取消
)

func (ywp YongWangPoints) getUrl() string {
	if IS_PROD {
		return URL_PROD
	}
	return URL_TEST
}

func (ywp YongWangPoints) getAppID() string {
	return KEYWORDS_APPID
}

func (ywp YongWangPoints) getStoreCode() string {
	return KEYWORDS_STORE_CODE
}

func (ywp YongWangPoints) getVersion() string {
	return KEYWORDS_VERSION
}

func (ywp YongWangPoints) getTokenID() string {
	randString, _ := helper.UUID{}.String()
	return randString
}

func (ywp YongWangPoints) getTimestamp() int64 {
	return carbon.Now().TimestampMilli()
}

// 构建请求头
func (ywp YongWangPoints) buildHeader(sign string) map[string]string {
	header := make(map[string]string)
	header["Content-Type"] = "application/json"
	header[HEADER_APPID] = ywp.getAppID()
	header[HEADER_VERSION] = ywp.getVersion()
	header[HEADER_SIGN] = sign
	return header
}

func NewYongwangPoints() PointsInterface {
	return &YongWangPoints{}
}

// 设置私钥
func (ywp YongWangPoints) SetPrivKey(pkey []byte) (PrivateKey *rsa.PrivateKey) {
	block, _ := pem.Decode(pkey)
	if block == nil {
		fmt.Println("pem.Decode err")
		return
	}

	private, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		fmt.Println("ParsePKCS8PrivateKey err", err)
		return
	}

	return private.(*rsa.PrivateKey)
}

// 生成签名
func (ywp YongWangPoints) GetSign(params map[string]interface{}) (sign string) {
	// key升序
	var keys []string
	for k := range params {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	// 拼接value
	var values string
	for _, k := range keys {
		switch (params[k]).(type) {
		case string:
			values = values + (params[k]).(string)
		case int, int32, int64:
			values = values + strconv.Itoa((params[k]).(int))
		}
	}
	// 获取私钥
	PrivateKeyContents, _ := os.ReadFile("./etc/cert/yongwang/private_key.pem")
	PrivateKey := ywp.SetPrivKey(PrivateKeyContents)
	h := crypto.Hash.New(crypto.SHA1)
	h.Write([]byte(values))
	hashedData := h.Sum(nil)

	signature, err := rsa.SignPKCS1v15(rand.Reader, PrivateKey, crypto.SHA1, hashedData)
	if err != nil {
		fmt.Printf("Error from signing: %s\n", err)
		return ""
	}
	return base64.StdEncoding.EncodeToString(signature)
}

// 通用请求参数
type YongwangCommonReq struct {
	TokenId     string `json:"tokenId"`     // 随机字符串
	AppId       string `json:"appId"`       // 应用ID
	Timestamp   int64  `json:"timestamp"`   // 时间戳 毫秒
	Sign        string `json:"sign"`        // 签名
	AccessToken string `json:"accessToken"` // 授权Token
	StoreCode   string `json:"storeCode"`   // 门店编码
	ThirdId     string `json:"thirdId"`     // 第三方会员ID 非必填
	OpenId      string `json:"openId"`      // 会员ID
}

// 会员授权请求
// 2 获取会员授权信息
type YongwangMemberAuthReq struct {
	TokenId   string `json:"tokenId"`   // 随机字符串
	AppId     string `json:"appId"`     // 应用ID
	Timestamp int64  `json:"timestamp"` // 时间戳 毫秒
	StoreCode string `json:"storeCode"` // 门店编码
	Ticket    string `json:"ticket"`    // 票据
}

type YongwangMemberAuthRsp struct {
	Code      int    `json:"code"` // 200成功，其他失败
	Message   string `json:"message"`
	Timestamp int64  `json:"timestamp"`
	Data      struct {
		OpenId      string `json:"openId"`      // 会员id
		MobileNo    string `json:"mobileNo"`    // 手机号
		AccessToken string `json:"accessToken"` // 授权Token
		Expires     int64  `json:"expires"`     // 授权Token有效 分钟
	} `json:"data"`
}

// 3 会员查询
type YongwangMemberQueryReq YongwangCommonReq
type YongwangMemberQueryRsp struct {
	Code      int    `json:"code"` // 200成功，其他失败
	Message   string `json:"message"`
	Timestamp int64  `json:"timestamp"`
	Data      struct {
		StoreCode    string  `json:"storeCode"`    // 门店编码
		OpenId       string  `json:"openId"`       // 会员id
		Nickname     string  `json:"nickname"`     // 会员昵称
		HeadImgUrl   string  `json:"head_img_url"` // 会员头像
		Status       int64   `json:"status"`       // 状态
		FrozenFlag   int64   `json:"frozenFlag"`   // 是否冻结
		ConsumePoint float64 `json:"consumePoint"` // 可用积分
		LevelCode    string  `json:"levelCode"`    // 会员等级编码
		LevelName    string  `json:"levelName"`    // 会员等级名称
		Freshman     bool    `json:"freshman"`     // 是否新人 true是 false否
	} `json:"data"`
}

func (ywp YongWangPoints) MemberInfo(ctx context.Context) (data interface{}, err error) {
	QueryURL := ywp.getUrl() + API_MEMBER_QUERY
	params := YongwangMemberQueryReq{
		TokenId:     ywp.getTokenID(),
		AppId:       ywp.getAppID(),
		Timestamp:   ywp.getTimestamp(),
		StoreCode:   ywp.getStoreCode(),
		AccessToken: "",
		OpenId:      "",
	}

	bytes, _ := json.Marshal(params)
	var PostData map[string]interface{}
	json.Unmarshal(bytes, &PostData)
	sign := ywp.GetSign(PostData)

	params.Sign = sign
	header := ywp.buildHeader(sign)
	statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", QueryURL, header, params)
	var rsp YongwangMemberQueryRsp
	json.Unmarshal(bytes, &rsp)
	if statusCode != 200 || rsp.Code != 200 || err != nil {
		return rsp, errorx.New(rsp.Message, int(rsp.Code))
	}
	return rsp, nil
}

// 5、6 会员积分使用及冲正
type YongwangPointsConsumeReq struct {
	TokenId      string  `json:"tokenId"`      // 随机字符串
	AppId        string  `json:"appId"`        // 应用ID
	Timestamp    int64   `json:"timestamp"`    // 时间戳 毫秒
	Sign         string  `json:"sign"`         // 签名
	AccessToken  string  `json:"accessToken"`  // 授权Token
	StoreCode    string  `json:"storeCode"`    // 门店编码
	ThirdId      string  `json:"thirdId"`      // 第三方会员ID 非必填
	OpenId       string  `json:"openId"`       // 会员ID
	OrderNo      string  `json:"orderNo"`      // 订单号
	PayNo        string  `json:"payNo"`        // 事务号
	TradeBalance float64 `json:"tradeBalance"` // 金额 非必填
	TradePoint   float64 `json:"tradePoint"`   // 积分
	SrcOrderNo   string  `json:"srcOrderNo"`   // 原订单号 冲正时带上
}
type YongwangPointsConsumeRsp struct {
	Code      int    `json:"code"` // 200成功，其他失败
	Message   string `json:"message"`
	Timestamp int64  `json:"timestamp"`
}

func (ywp YongWangPoints) PointsConsume(ctx context.Context, db *gorm.DB, salesID, openid string,
	orderID string, tradeAmount float64, mallId string) (err error) {
	QueryURL := ywp.getUrl() + API_POINTS_CONSUME
	params := YongwangPointsConsumeReq{
		TokenId:     ywp.getTokenID(),
		AppId:       ywp.getAppID(),
		Timestamp:   ywp.getTimestamp(),
		StoreCode:   ywp.getStoreCode(),
		AccessToken: "",
		OpenId:      "",
	}

	bytes, _ := json.Marshal(params)
	var PostData map[string]interface{}
	json.Unmarshal(bytes, &PostData)
	sign := ywp.GetSign(PostData)

	params.Sign = sign
	header := ywp.buildHeader(sign)
	statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", QueryURL, header, params)
	var rsp YongwangPointsConsumeRsp
	json.Unmarshal(bytes, &rsp)
	if statusCode != 200 || rsp.Code != 200 || err != nil {
		return errorx.New(rsp.Message, int(rsp.Code))
	}
	return nil
}

func (ywp YongWangPoints) PointsReverse(ctx context.Context, db *gorm.DB, salesID, openid string,
	refundOrderID, orderID string, tradeAmount float64, mallId string) (err error) {
	QueryURL := ywp.getUrl() + API_POINTS_REVERSE
	params := YongwangPointsConsumeReq{
		TokenId:     ywp.getTokenID(),
		AppId:       ywp.getAppID(),
		Timestamp:   ywp.getTimestamp(),
		StoreCode:   ywp.getStoreCode(),
		AccessToken: "",
		OpenId:      "",
	}

	bytes, _ := json.Marshal(params)
	var PostData map[string]interface{}
	json.Unmarshal(bytes, &PostData)
	sign := ywp.GetSign(PostData)

	params.Sign = sign
	header := ywp.buildHeader(sign)
	statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", QueryURL, header, params)
	var rsp YongwangPointsConsumeRsp
	json.Unmarshal(bytes, &rsp)
	if statusCode != 200 || rsp.Code != 200 || err != nil {
		return errorx.New(rsp.Message, int(rsp.Code))
	}
	return nil
}

// 7.会员积分查询
type YongwangPointsQueryReq YongwangCommonReq

type YongwangPointsQueryRsp struct {
	Code      int    `json:"code"` // 200成功，其他失败
	Message   string `json:"message"`
	Timestamp int64  `json:"timestamp"`
	Data      struct {
		StoreCode    string  `json:"storeCode"`    // 门店编码
		OpenId       string  `json:"openId"`       // 会员ID
		ConsumePoint float64 `json:"consumePoint"` // 会员可用积分
	} `json:"data"`
}

func (ywp YongWangPoints) PointsQuery(ctx context.Context, salesID, openID, mallId string) (points float64, err error) {
	QueryURL := ywp.getUrl() + API_POINTS_QUERY
	params := YongwangPointsQueryReq{
		TokenId:     ywp.getTokenID(),
		AppId:       ywp.getAppID(),
		Timestamp:   ywp.getTimestamp(),
		StoreCode:   ywp.getStoreCode(),
		AccessToken: "",
		OpenId:      "",
	}

	bytes, _ := json.Marshal(params)
	var PostData map[string]interface{}
	json.Unmarshal(bytes, &PostData)
	sign := ywp.GetSign(PostData)

	params.Sign = sign
	header := ywp.buildHeader(sign)
	statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", QueryURL, header, params)
	var rsp YongwangPointsQueryRsp
	json.Unmarshal(bytes, &rsp)
	if statusCode != 200 || rsp.Code != 200 || err != nil {
		return 0, errorx.New(rsp.Message, int(rsp.Code))
	}
	return rsp.Data.ConsumePoint, nil
}

type YongwangOrderCreateReq struct {
	TokenId     string `json:"tokenId"`
	Timestamp   int64  `json:"timestamp"`
	StoreCode   string `json:"storeCode"`
	OutOrderNo  string `json:"outOrderNo"`
	ProductName string `json:"productName"`
	// ProductClassifyCode string  `json:"productClassifyCode"`
	// ProductClassify     string  `json:"productClassify"`
	ImgUrl     string  `json:"imgUrl"`
	ProductQty int64   `json:"productQty"`
	PayPoint   float64 `json:"payPoint"`
}
type YongwangOrderCreateRspData struct {
	PayCode           string  `json:"payCode"`           // 用于订单支付的支付码
	PreUrl            string  `json:"preUrl"`            // 用于跳转到支付页面的url前缀
	PayCodeExpireTime float64 `json:"payCodeExpireTime"` // 支付码过期时间，秒级别，例180秒
}
type YongwangOrderCreateRsp struct {
	Code      int                        `json:"code"` // 200成功，其他失败
	Message   string                     `json:"message"`
	Timestamp int64                      `json:"timestamp"`
	Data      YongwangOrderCreateRspData `json:"data"`
}

func (ywp YongWangPoints) OrderCreate(ctx context.Context, outOrderNo, productName, imgUrl string, productQty int64, payPoint float64) (res YongwangOrderCreateRspData, err error) {
	QueryURL := ywp.getUrl() + API_ORDER_CREATE
	params := YongwangOrderCreateReq{
		TokenId:     ywp.getTokenID(),
		Timestamp:   ywp.getTimestamp(),
		StoreCode:   ywp.getStoreCode(),
		OutOrderNo:  outOrderNo,
		ProductName: productName,
		ImgUrl:      imgUrl,
		ProductQty:  productQty,
		PayPoint:    payPoint,
	}

	bytes, _ := json.Marshal(params)
	var PostData map[string]interface{}
	json.Unmarshal(bytes, &PostData)
	sign := ywp.GetSign(PostData)
	header := ywp.buildHeader(sign)

	statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", QueryURL, header, params)
	var rsp YongwangOrderCreateRsp
	json.Unmarshal(bytes, &rsp)
	if statusCode != 200 || rsp.Code != 200 || err != nil {
		return res, errorx.New(rsp.Message, int(rsp.Code))
	}
	return rsp.Data, nil
}

type YongwangOrderCancelReq struct {
	TokenId    string `json:"tokenId"`    // 随机字符串
	Timestamp  int64  `json:"timestamp"`  // 时间戳
	PayCode    string `json:"payCode"`    // 支付编码
	OutOrderNo string `json:"outOrderNo"` // 外部订单号【大道】
}
type YongwangOrderCancelRsp struct {
	Code      int    `json:"code"` // 200成功，其他失败
	Message   string `json:"message"`
	Timestamp int64  `json:"timestamp"`
}

func (ywp YongWangPoints) OrderCancel(ctx context.Context, outOrderNo, payCode string) (err error) {
	QueryURL := ywp.getUrl() + API_ORDER_CANCEL
	params := YongwangOrderCancelReq{
		TokenId:    ywp.getTokenID(),
		Timestamp:  ywp.getTimestamp(),
		OutOrderNo: outOrderNo,
		PayCode:    payCode,
	}

	bytes, _ := json.Marshal(params)
	var PostData map[string]interface{}
	json.Unmarshal(bytes, &PostData)
	sign := ywp.GetSign(PostData)
	header := ywp.buildHeader(sign)

	statusCode, bytes, err := helper.Net{}.Request(ctx, "POST", QueryURL, header, params)
	var rsp YongwangOrderCancelRsp
	json.Unmarshal(bytes, &rsp)
	if statusCode != 200 || rsp.Code != 200 || err != nil {
		return errorx.New(rsp.Message, int(rsp.Code))
	}
	return nil
}

var ErrCode = map[int]string{
	-1:        "未知异常",
	0:         "失败",
	200:       "成功",
	5000:      "系统异常",
	106090001: "签名错误",
	106090002: "重复提交数据",
	106090003: "Ticket不存在或已失效",  // 重新调用会员授权请求
	106090004: "授权Token不存在或已失效", // 重新调用会员授权请求
	106090005: "会员OpenId不存在",
	106090006: "会员不存在或已注销",
	106090007: "会员积分不足",
	106090008: "会员已冻结",
	106090009: "会员积分获取已达到上限",
	106090010: "会员积分使用已达到上限",
	106090011: "会员已取消绑定", // 重新调用会员授权请求
	106090012: "门店不存在或已关闭",
	106090013: "appId不存在",
	106090014: "生成OpenId失败",
	106090015: "会员绑定失败",
	106090016: "非法的IP",
	106090017: "原订单号不存在",
	106090018: "订单号已存在",
	106090019: "积分必须大于0",
	106090020: "积分抵扣金额必须大于0",
	106099999: "禁止操作", // 禁止任何操作
	301070006: "验签失败，当前接口没有访问权限",
	301070007: "验签失败",
	301070008: "验签失败,ip不在白名单内",
	301070009: "验签失败,缺少必要的请求头参数",
	301070010: "验签失败,密钥未生效",
	301070011: "验签失败,密钥已失效",
	301070012: "验签失败,appid未授权",
	301070013: "验签失败,appid已禁用",
	502053195: "品牌不存在",
}
